home *** CD-ROM | disk | FTP | other *** search
/ Qu.......ke Neue Level / KroGer Software GmbH - Qu_ke.iso / UTILITY / PRG8.ZIP / F_WAD2.C < prev    next >
C/C++ Source or Header  |  1996-03-03  |  11KB  |  364 lines

  1. /*
  2.  * Copyright (C) 1996 by Raphael Quinet.  All rights reserved.
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and
  5.  * its documentation for any purpose and without fee is hereby
  6.  * granted, provided that the above copyright notice appear in all
  7.  * copies and that both that copyright notice and this permission
  8.  * notice appear in supporting documentation.  If more than a few
  9.  * lines of this code are used in a program which displays a copyright
  10.  * notice or credit notice, the following acknowledgment must also be
  11.  * displayed on the same screen: "This product includes software
  12.  * developed by Raphael Quinet for use in the Quake Editing Utilities
  13.  * project."  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
  14.  * IMPLIED WARRANTY.
  15.  *
  16.  * More information about the QEU project can be found on the WWW:
  17.  * "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
  18.  * mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
  19.  */
  20.  
  21. /*
  22.  * F_WAD2.C - Read and write Quake WAD2 files.
  23.  */
  24.  
  25. #include "qeu.h"
  26. #include "q_misc.h"
  27. #include "q_files.h"
  28. #include "f_bitmap.h"
  29. #include "f_wad2.h"
  30.  
  31. /*
  32.  * Read the WAD2 directory into memory.  The optional offset to the
  33.  * start of the WAD2 file is given in "offset".  The number of entries in
  34.  * the directory is returned in *dirsize_r.
  35.  */
  36. WAD2DirPtr ReadWAD2Directory(FILE *wadfile, UInt32 offset, UInt16 *dirsize_r)
  37. {
  38.   WAD2DirPtr  dir;
  39.   UInt32      pos, size;
  40.   UInt16      max, i;
  41.  
  42.   *dirsize_r = 0;
  43.   if (wadfile == NULL)
  44.     return NULL;
  45.   if ((fseek(wadfile, offset, SEEK_SET) < 0)
  46.       || (ReadMagic(wadfile) != FTYPE_WAD2)
  47.       || (ReadInt32(wadfile, &size) == FALSE)
  48.       || (ReadInt32(wadfile, &pos) == FALSE)
  49.       || (size == 0L)
  50.       || (size > 65535L)
  51.       || (fseek(wadfile, pos, SEEK_SET) < 0))
  52.     return NULL;
  53.   dir = (WAD2DirPtr)QMalloc(size * sizeof(struct WAD2Directory));
  54.   max = (UInt16)size;
  55.   for (i = 0; i < max; i++)
  56.     {
  57.       if (ReadBytes(wadfile, &dir[i], sizeof(struct WAD2Directory)) == FALSE)
  58.     {
  59.       QFree(dir);
  60.       return NULL;
  61.     }
  62.       dir[i].offset = SwapInt32(dir[i].offset);
  63.       dir[i].size = SwapInt32(dir[i].size);
  64.       dir[i].dsize = SwapInt32(dir[i].dsize);
  65.     }
  66.   *dirsize_r = max;
  67.   return dir;
  68. }
  69.  
  70.  
  71. /*
  72.  * Return the index number of the first entry matching "entryname".
  73.  * A number greater or equal to dirsize is returned if no match is found.
  74.  */
  75. UInt16 FindWAD2Entry(WAD2DirPtr dir, UInt16 dirsize, char *entryname)
  76. {
  77.   UInt16 i;
  78.  
  79.   if (dir == NULL)
  80.     ProgError("BUG: Cannot find entry in NULL directory");
  81.   for (i = 0; i < dirsize; i++)
  82.     if (!strnicmp(dir[i].name, entryname, 16))
  83.       return i;
  84.   return i;
  85. }
  86.  
  87.  
  88. /*
  89.  * Print the contents of the WAD2 directory in "outf".
  90.  */
  91. void DumpWAD2Directory(FILE *outf, WAD2DirPtr dir, UInt16 dirsize)
  92. {
  93.   UInt16 i;
  94.   UInt32 sum;
  95.   char   buf[17];
  96.  
  97.   if (outf == NULL || dir == NULL || dirsize == 0)
  98.     return;
  99.   fprintf(outf, "num    offset     size    size   type cmpr  entry name\n");
  100.   fprintf(outf, "       (hex)      (dec)   (dec)\n");
  101.   sum = 0L;
  102.   for (i = 0; i < dirsize; i++)
  103.     {
  104.       strncpy(buf, dir[i].name, 16);
  105.       buf[16] = '\0';
  106.       fprintf(outf, "%3u  0x%08lx  %6ld  %6ld   %c    %d    %s\n",
  107.           i, dir[i].offset, dir[i].size, dir[i].dsize,
  108.           dir[i].dtype, dir[i].compression, buf);
  109.       sum += dir[i].size;
  110.     }
  111.   fprintf(outf, "\nTotal size for %3u entries:  %7lu bytes.\n", dirsize, sum);
  112.   fprintf(outf, "Size of the WAD2 directory:  %7lu bytes.\n",
  113.       (UInt32)dirsize * (UInt32)sizeof(struct WAD2Directory));
  114.   fprintf(outf, "Total (header + data + dir): %7lu bytes.\n",
  115.       12L + sum + (UInt32)dirsize * (UInt32)sizeof(struct WAD2Directory));
  116. }
  117.  
  118.  
  119. /*
  120.  * Extract all entries from a WAD2 file and save them in separate
  121.  * files.  The files will be saved in the directory "prefixpath".  If
  122.  * "outf" is not null, progress information will be printed in it.
  123.  */
  124. Bool UnWAD2File(FILE *outf, FILE *wadfile, UInt32 offset, WAD2DirPtr dir,
  125.         UInt16 dirsize, UInt16 entrynum, char *prefixpath,
  126.         Bool convert)
  127. {
  128.   char       *newname;
  129.   char       *p;
  130.   FILE       *newfile;
  131.   FILE       *indexfile;
  132.   UInt16      i;
  133.   UInt32      sum;
  134.   BitMap     *bmptr;
  135.   struct RGB *palptr = NULL;
  136.  
  137.   if (wadfile == NULL || dir == NULL || dirsize == 0)
  138.     return FALSE;
  139.   if (prefixpath == NULL)
  140.     prefixpath = ".";
  141.   if (convert == TRUE)
  142.     {
  143.       for (i = 0; i < dirsize; i++)
  144.     if (dir[i].dtype == '@' && !stricmp(dir[i].name, "PALETTE"))
  145.       break;
  146.       if (i < dirsize)
  147.     palptr = ReadPalette256(wadfile, offset + dir[i].offset);
  148.       if (palptr == NULL)
  149.     return FALSE;
  150.     }
  151.   newname = (char *)QMalloc(strlen(prefixpath) + 16 + 4 + 2);
  152.   strcpy(newname, prefixpath);
  153.   p = &newname[strlen(newname) - 1];
  154. #ifdef QEU_DOS
  155.   if (*p != '\\')
  156.     {
  157.       p++;
  158.       *p = '\\';
  159.     }
  160. #else
  161.   if (*p != '/')
  162.     {
  163.       p++;
  164.       *p = '/';
  165.     }
  166. #endif
  167.   p++;
  168.   strcpy(p, QEU_INDEX_FILE);
  169.   if (outf != NULL)
  170.     fprintf(outf, "Creating index file %s\n", newname);
  171.   CreatePathToFile(newname);
  172.   indexfile = fopen(newname, "a");
  173.   fprintf(indexfile, "BEGIN WAD2\n");
  174.   sum = 0L;
  175.   for (i = 0; i < dirsize; i++)
  176.     {
  177.       if (entrynum < dirsize && i != entrynum)
  178.     continue; /* horrible trick... */
  179.       strcpy(p, dir[i].name);
  180.       if (dir[i].dtype == '@')
  181.     strcat(p, ".lmp");
  182.       else if (dir[i].dtype == 'B')
  183.     if (convert == TRUE)
  184.       strcat(p, ".bmp");
  185.     else
  186.       strcat(p, ".pic");
  187.       else if (dir[i].dtype == 'E')
  188.     if (convert == TRUE)
  189.       strcat(p, ".bmp");
  190.     else
  191.       strcat(p, ".bit");
  192.       else
  193.     strcat(p, ".xxx");
  194.       if (outf != NULL)
  195.     fprintf(outf, "Saving %6ld bytes to %s\n", dir[i].size, newname);
  196.       CreatePathToFile(newname);
  197.       newfile = fopen(newname, "wb");
  198.       if (newfile == NULL)
  199.     {
  200.       fclose(indexfile);
  201.       QFree(newname);
  202.       return FALSE;
  203.     }
  204.       /* BMP conversion stuff */
  205.       if (convert == TRUE && (dir[i].dtype == 'B' || dir[i].dtype == 'E'))
  206.     {
  207.       fprintf(indexfile, "+ %s %c #= %s\n", dir[i].name, dir[i].dtype, p);
  208.       if (dir[i].dtype == 'E')
  209.         {
  210.           if (!stricmp(dir[i].name, "CONCHARS"))
  211.         bmptr = ReadRawBitMap(wadfile, offset + dir[i].offset,
  212.                       128, 128);
  213.           else if (!stricmp(dir[i].name, "CONBACK"))
  214.         bmptr = ReadRawBitMap(wadfile, offset + dir[i].offset,
  215.                       320, 200);
  216.           else
  217.         bmptr = NULL;
  218.         }
  219.       else
  220.         bmptr = ReadBitMap(wadfile, offset + dir[i].offset);
  221.       if (bmptr == NULL)
  222.         {
  223.           fclose(newfile);
  224.           fclose(indexfile);
  225.           QFree(newname);
  226.           return FALSE;
  227.         }
  228.       sum += SaveBMP(newfile, bmptr, palptr);
  229.     }
  230.       else
  231.     {
  232.       fprintf(indexfile, "+ %s %c = %s\n", dir[i].name, dir[i].dtype, p);
  233.       if ((fseek(wadfile, offset + dir[i].offset, SEEK_SET) < 0)
  234.           || (CopyBytes(newfile, wadfile, dir[i].size) == FALSE))
  235.         {
  236.           fclose(newfile);
  237.           fclose(indexfile);
  238.           QFree(newname);
  239.           return FALSE;
  240.         }
  241.       sum += dir[i].size;
  242.     }
  243.       fclose(newfile);
  244.     }
  245.   if (outf != NULL && entrynum >= dirsize)
  246.     fprintf(outf, "Saved %lu bytes in %u files.\n", sum, dirsize);
  247.   fprintf(indexfile, "END WAD2\n");
  248.   fclose(indexfile);
  249.   QFree(newname);
  250.   return TRUE;
  251. }
  252.  
  253.  
  254. /* ----------------------------------------------------------------------------
  255.  * NOTE: How to save a wad2 file:
  256.  *
  257.  * UInt32     count;  - used by the saving routines
  258.  * WAD2DirPtr dir;    - WAD2 directory structure (created step by step)
  259.  * UInt16     n;      - number of entries in WAD2 directory (idem)
  260.  *
  261.  * WriteWAD2Header(f, &count, &dir, &n);                - write the header
  262.  * size = WriteSomething(f, ...);                       - save one entry
  263.  * AddWAD2Entry(f, &count, &dir, &n, name, size, type); - add entry to dir.
  264.  * size = WriteSomethingElse(f, ...);                   - save another entry
  265.  * AddWAD2Entry(f, &count, &dir, &n, othername, size, type); - add to dir. too
  266.  * totalsize = WriteWAD2Directory(f, &count, dir, n);  - write the directory
  267.  */
  268.  
  269. /*
  270.  * Write the WAD2 header to the file.  The header will be modified later,
  271.  * when the directory is written to the file.
  272.  */
  273. Bool WriteWAD2Header(FILE *wadfile, UInt32 *count_r, WAD2DirPtr *dir_r,
  274.              UInt16 *dirsize_r)
  275. {
  276.   char buf[100];
  277.  
  278.   sprintf(buf, "WAD2********\r\nQEU %s\r\n", QEU_VERSION);
  279.   if ((wadfile == NULL)
  280.       || (WriteBytes(wadfile, buf, (UInt32)strlen(buf)) == FALSE))
  281.     return FALSE;
  282.   *dir_r = NULL;
  283.   *count_r = (UInt32)strlen(buf);
  284.   *dirsize_r = 0;
  285.   return TRUE;
  286. }
  287.  
  288.  
  289. /*
  290.  * Add a new entry to the WAD2 directory.  This entry should have been
  291.  * saved previously and be "entrysize" bytes long.  It will be stored
  292.  * in the WAD2 directory under the name "entryname".
  293.  * All object saving routines in this package return the number of bytes
  294.  * written, so that number can be passed directly to this routine.
  295.  */
  296. Bool AddWAD2Entry(FILE *wadfile, UInt32 *count_r, WAD2DirPtr *dir_r,
  297.           UInt16 *dirsize_r, char *entryname, UInt32 entrysize,
  298.           UInt8 entrytype)
  299. {
  300.   UInt16 n;
  301.   UInt32 compressedsize;
  302.   char   buf[17];
  303.  
  304.   if (wadfile == NULL || *count_r == 0L)
  305.     return FALSE;
  306.   n = *dirsize_r;
  307.   if (n == 0)
  308.     *dir_r = (WAD2DirPtr)QMalloc((UInt32)sizeof(struct WAD2Directory));
  309.   else
  310.     *dir_r = (WAD2DirPtr)QRealloc(*dir_r, (UInt32)(n + 1)
  311.                   * (UInt32)sizeof(struct WAD2Directory));
  312.   compressedsize = entrysize; /* don't know how to compress, so... */
  313.   strncpy(buf, entryname, 16);
  314.   buf[16] = '\0';
  315.   QStrNCpy((*dir_r)[n].name, strupr(buf), 16);
  316.   (*dir_r)[n].offset = *count_r;
  317.   (*dir_r)[n].size = compressedsize;
  318.   (*dir_r)[n].dsize = entrysize;
  319.   (*dir_r)[n].dtype = entrytype;
  320.   (*dir_r)[n].compression = 0;
  321.   (*dir_r)[n].padding = 0;
  322.   *count_r = *count_r + compressedsize;
  323.   *dirsize_r = n + 1;
  324.   return TRUE;
  325. }
  326.  
  327.  
  328. /*
  329.  * Write the WAD2 directory to the file.  This should only be done
  330.  * after all entries have been saved (using the appropriate
  331.  * Write... routine) and registered (using AddWAD2Entry).  The WAD2
  332.  * header is updated so that it points to the directory.
  333.  *
  334.  * This routine returns the total number of bytes taken by the WAD2
  335.  * file (header + all entries + directory).  It is thus possible to
  336.  * include a WAD2 file in another WAD2 file or in a PACK file.
  337.  */
  338. UInt32 WriteWAD2Directory(FILE *wadfile, UInt32 *count_r, WAD2DirPtr dir,
  339.               UInt16 dirsize)
  340. {
  341.   UInt32 size, pos;
  342.   UInt16 i;
  343.  
  344.   pos = *count_r;
  345.   if (wadfile == NULL || pos == 0L)
  346.     return 0L;
  347.   *count_r = 0L; /* invalidate the counter */
  348.   size = (UInt32)dirsize;
  349.   if ((fseek(wadfile, 4L - (Int32)(pos), SEEK_CUR) < 0)
  350.       || (WriteInt32(wadfile, &size) == FALSE)
  351.       || (WriteInt32(wadfile, &pos) == FALSE)
  352.       || (fseek(wadfile, (Int32)(pos) - 12L, SEEK_CUR) < 0))
  353.     return 0L;
  354.   for (i = 0; i < dirsize; i++)
  355.     if ((WriteInt32(wadfile, &(dir[i].offset)) == FALSE)
  356.     || (WriteInt32(wadfile, &(dir[i].size)) == FALSE)
  357.     || (WriteInt32(wadfile, &(dir[i].dsize)) == FALSE)
  358.     || (WriteBytes(wadfile, &(dir[i].dtype), 20L) == FALSE))
  359.       return 0L;
  360.   return size * (UInt32)sizeof(struct WAD2Directory) + pos;
  361. }
  362.  
  363. /* end of file */
  364.